import pinyin from 'pinyin';
import { SearchItem } from '../type';

const MIN_SCORE = -99999;

class Index {
    id: number = 0;
    key: string = '';
    score: number = 0;
    isSimple: boolean = false;

    constructor(id: number, key: string, isSimple: boolean) {
        this.id = id;
        this.key = key;
        this.isSimple = isSimple;
    }
}

export default class Searcher {
    private indexs: Index[] = [];

    public load(searchItems: SearchItem[]) {
        this.indexs = [];

        for (let i = 0; i < searchItems.length; i++) {
            let item = searchItems[i];
            let fullKey = '';
            let simpleKey = '';

            if (this.existChinese(item.key)) {
                simpleKey = this.ExtractSimpleLetter(item.key);
            }
            else {
                fullKey = item.key;
                simpleKey = this.ExtractSimpleLetter(item.key);
            }

            if (fullKey != '') this.indexs.push(new Index(item.id, fullKey, false));
            if (simpleKey != '') this.indexs.push(new Index(item.id, simpleKey, true));
        }
    }

    public search(query: string): number[] {
        let ids: number[] = [];
        if (query == '') return ids;

        // 计算得分
        for (let index of this.indexs) {
            index.score = this.calMatchScore(query, index);
        }

        // 降序排序
        this.indexs.sort((a, b) => b.score - a.score);

        // 取出前 8 个的 id
        for (let index of this.indexs) {
            if (index.score == MIN_SCORE) break;
            if (ids.includes(index.id)) continue;
            ids.push(index.id);
            if (ids.length >= 8) break;
        }

        return ids;
    }

    private calMatchScore(content: string, index: Index): number {
        if (!index.key.toLowerCase().startsWith(content.toLowerCase())) return MIN_SCORE; // 搜索内容与目标开头不匹配

        let score = content.length - index.key.length; // 差异越大分越小
        // 当 content: wx; WeXin(wx); wx; wxj; 希望的分数为 wx>WeXin(wx)>wxj
        score += index.isSimple ? 0 : 0.5;
        return score;
    }

    /**提取字符串每个词的首字母，返回小写字母字符串 */
    private ExtractSimpleLetter(str: string): string {
        str = str.trim();
        let simpleLetter = '';

        /**上一个字符是字母*/
        let isPreviousLetter = false;
        for (let i = 0; i < str.length; i++) {
            let char = str.charAt(i);

            if (i == 0) { // 第一个字符
                if (this.isChineseChar(char)) { // 是汉字
                    simpleLetter += pinyin(char, { style: pinyin.STYLE_FIRST_LETTER });
                }
                else { // 非汉字
                    simpleLetter += char;
                    isPreviousLetter = this.isLetter(char);
                }
            }
            else {
                if (this.isChineseChar(char)) { // 是汉字
                    simpleLetter += pinyin(char, { style: pinyin.STYLE_FIRST_LETTER });
                    isPreviousLetter = false;
                }
                else if (this.isLetter(char)) { // 是字母
                    if (!isPreviousLetter) { // 如果上一个字符不是字母，那么需要提取当前字母，无论大小写
                        simpleLetter += char;
                    }
                    else if (this.isUpperCaseLetter(char)) { // 如果上一个字符是字母，则只有当前字母为大写时才需要提取
                        simpleLetter += char;
                    }
                    isPreviousLetter = true;
                }
                else if (char != ' ') { // 当不是汉字、字母和空格时，需要提取
                    simpleLetter += char;
                    isPreviousLetter = false;
                }
                else isPreviousLetter = false;
            }
        }

        // 如果只有一个词，就不生成简写字母
        if (simpleLetter.length == 1 && this.isFullLetter(str)) return '';
        return simpleLetter.toLocaleLowerCase();
    }

    /**存在汉字 */
    private existChinese(str: string): boolean {
        for (let i = 0; i < str.length; i++) {
            if (this.isChineseChar(str.charAt(i))) return true;
        }
        return false;
    }

    /**全是字母 */
    private isFullLetter(str: string): boolean {
        for (let i = 0; i < str.length; i++) {
            if (!this.isLetter(str.charAt(i))) return false;
        }
        return true;
    }

    /**是汉字 */
    private isChineseChar(char: string): boolean {
        return /^[\u4e00-\u9fa5]$/.test(char);
    }

    /**是字母 */
    private isLetter(char: string): boolean {
        return /^[a-zA-Z]$/.test(char);
    };

    /**是小写字母 */
    private isLowCaseLetter(char: string): boolean {
        return /^[a-z]$/.test(char);
    };

    /**是大写字母 */
    private isUpperCaseLetter(char: string): boolean {
        return /^[A-Z]$/.test(char);
    }
}
